package com.mudrov.collections.realization;

import java.util.Collection;
import java.util.Iterator;

import com.mudrov.collections.interfaces.CollectionToQueue;

public class LinkedListForQueue<E> implements CollectionToQueue<E> {

	protected Node head;
	protected Node tail;
	protected int size = 0;
	
	@Override
	public boolean add(E e) {
		++size;
		if(head == null){
			tail = head = new Node(e);
			return true;
		}
		tail.next = new Node(e,tail);
		tail = tail.next;
		return true;
	}

	@Override
	public boolean addAll(Collection<? extends E> c) {
		for(E element : c)
			add(element);
		return true;
	}

	@Override
	public void clear() {
		head = null;
		tail = null;
		size = 0;
	}

	@Override
	public boolean contains(Object o) {
		for(E element : this)
			if(element.equals(o))
				return true;
		return false;
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		for(Object element : c)
			if(!contains(element))
				return false;
		return true;
	}

	@Override
	public boolean isEmpty() {
		return head == null;
	}

	@Override
	public Iterator<E> iterator() {
		return new LinkedListIterator();
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean remove(Object o) {
		Node toDelete = findElement((E)o);
		if(toDelete == null)
			return false;
		if(toDelete == head)
			head = head.next;
		if(toDelete == tail)
			tail = tail.prev;
		if(toDelete.next != null)
			toDelete.next.prev = toDelete.prev;
		if(toDelete.prev != null)
			toDelete.prev.next = toDelete.next;
		--size;
		return true;
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		boolean hasDeleted = false;
		for(Object element : c)
			if(remove(element))
				hasDeleted = true;
		return hasDeleted;
	}
	
	@Override
	public boolean retainAll(Collection<?> c) {
		boolean hasDeleted = false;
		Node current = head;
		while(current != null){
			if(!c.contains(current.element)){
				remove(current.element);
				hasDeleted = true;
			}
			current = current.next;
		}
		return hasDeleted;		
	}

	private Node findElement(E element){
		Node current = head;
		while(current != null){
			if(current.element.equals(element))
				return current;
			current = current.next;
		}
		return null;
	}
	@Override
	public int size() {
		return size;
	}

	@Override
	public Object[] toArray() {
		Object[] arrayToReturn = new Object[size];
		int i = 0;
		for(E element : this)
			arrayToReturn[i++] = element;
		return arrayToReturn;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T[] toArray(T[] a) {
		T[] arrayToReturn = (T[])new Object[size];
		int i = 0;
		for(E element : this)
			arrayToReturn[i++] = (T)element;
		return arrayToReturn;
	}
	
	protected class Node{
		
		public E element;
		public Node next;
		public Node prev;
		
		public Node(E element, Node prev){
			this.element = element;
			this.prev = prev;
		}
		public Node(E element){
			this.element = element;
		}
	}

	public class LinkedListIterator implements Iterator<E>{

		private Node current = head;
		@Override
		public boolean hasNext() {
			return current != null;
		}

		@Override
		public E next() {
			E toReturn = current.element;
			current = current.next;
			return toReturn;
		}

		@Override
		public void remove() {
			if(current == null)
				return;
			if(current.next != null)
				current.next.prev = current.prev;
			if(current.prev != null)
				current.prev.next = current.next;
			--size;
			current = current.next;
		}
		
	}
	
}
